package net.gdface.utils;

import com.google.common.base.Function;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkArgument;
/**
 * 基于GUAVA {@link LoadingCache}实现类型转转换接口{@link Function},
 * 当一个输入K的计算结果已经存在于缓存时，直接返回，无需再次计算，
 * 避免对同一个输入数据多次重复计算。
 * @author guyadong
 *
 * @param <K> 输入参数类型
 * @param <V> 输出参数类型
 */
public class FunctionCached<K,V> implements Function<K, V> {
	private final LoadingCache<K, V> cache;
	private final Function<K, V> getterFunction;
	private final V defaultValue;
	/**
	 * 构造方法
	 * @param getterFunction 原类型转换接口实现
	 * @param defaultValue    K为{@code null}时返回的默认值
	 */
	public FunctionCached(final Function<K, V> getterFunction,V defaultValue){
		this.getterFunction = checkNotNull(getterFunction,"getterFunction is null");
		/**  输入参数不可以是缓存实例  */
		checkArgument(!(getterFunction instanceof FunctionCached),"getterFunction must not be instance of %s",getClass().getName());
		this.defaultValue = defaultValue;
		this.cache = CacheBuilder.newBuilder().build(new CacheLoader<K, V>(){
			@Override
			public V load(K key) throws Exception {
				return getterFunction.apply(key);
			}});
	}
	/**
	 * 构造方法,
	 * K 为{@code null}时返回{@code null}
	 * @param getterFunction 原类型转换接口实现
	 */
	public FunctionCached(Function<K, V> getterFunction){
		this(getterFunction, null);
	}
	/**
	 * 非缓存调用
	 * @param key
	 * @return {@code key}为{@code null}返回{@link #defaultValue}
	 */
	public V getUncached(K key){
		return null == key ? defaultValue : getterFunction.apply(key);
	}
	/**
	 * 缓存调用
	 * @param key
	 * @return {@code key}为{@code null}返回{@link #defaultValue}
	 */
	public V get(K key){
		if(null != key){
			return cache.getUnchecked(key);
		}
		return defaultValue;
	}
	
	/**
	 * 缓存调用
	 * @see #get(Object)
	 * @see com.google.common.base.Function#apply(java.lang.Object)
	 */
	@Override
	public V apply(K input) {
		return get(input);
	}
	/**
	 * 返回{@code getterFunction}的{@link FunctionCached}实例,
	 * 如果{@code getterFunction}为{@link FunctionCached}实例,则直接返回，否则创建新实例
	 * @param getterFunction
	 * @param defaultValue
	 * @see #FunctionCached(Function, Object)
	 */
	public static <K, V> FunctionCached<K, V> of(Function<K, V> getterFunction,V defaultValue){
		if(getterFunction instanceof FunctionCached){
			return (FunctionCached<K, V>) getterFunction;
		}
		return new FunctionCached<K, V>(getterFunction, defaultValue); 
	}
	/**
	 * 返回{@code getterFunction}的{@link FunctionCached}实例(默认实例为{@code null})
	 * @param getterFunction
	 * @see #of(Function, Object)
	 */
	public static <K, V> FunctionCached<K, V> of(Function<K, V> getterFunction){
		return of(getterFunction,null); 
	}
}
